home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 005 / calcpas.arc / CALC.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1980-01-01  |  33.3 KB  |  1,259 lines

  1.  
  2.  
  3. { This program is hereby donated to the public domain                }
  4. { for non commercial use only                                        }
  5.  
  6. {Here is a note to the compiler:                                     }
  7. {$R-,U-,V-,X-,C-}
  8.  
  9. program MicroCalc;
  10.  
  11. const
  12.   FXMax: Char  = 'G';  { Maximum number of columns in spread sheet   }
  13.   FYMax        = 21;   { Maximum number of lines in spread sheet     }
  14.  
  15. type
  16.   Anystring   = string[70];
  17.   SheetIndex  = 'A'..'G';
  18.   Attributes  = (Constant,Formula,Txt,OverWritten,Locked,Calculated);
  19.  
  20. { The spreadsheet is made out of Cells every Cell is defined as      }
  21. { the following record:}
  22.  
  23.   CellRec    = record
  24.     CellStatus: set of Attributes; { Status of cell (see type def.)  }
  25.     Contents:   String[70];        { Contains a formula or some text }
  26.     Value:      Real;              { Last calculated cell value      }
  27.     DEC,FW:     0..20;             { Decimals and Cell Whith         }
  28.   end;
  29.  
  30.   Cells      =  array[SheetIndex,1..FYMax] of CellRec;
  31.  
  32. const
  33.   XPOS: array[SheetIndex] of integer = (3,14,25,36,47,58,68);
  34.  
  35. var
  36.   Sheet:         Cells;             { Definition of the spread sheet }
  37.   FX:            SheetIndex;        { Culumn of current cell         }
  38.   FY:            Integer;           { Line of current cell           }
  39.   Ch:            Char;              { Last read character            }
  40.   MCFile:        file of CellRec;   { File to store sheets in        }
  41.   AutoCalc:      boolean;           { Recalculate after each entry?  }
  42.  
  43.  
  44.  { For easy reference the procedures and functions are grouped in mo-}
  45.  { dules called MC-MOD00 through MC-MOD05.                           }
  46.  
  47.  
  48.  {.PA}
  49. {*******************************************************************}
  50. {*  SOURCE CODE MODULE: MC-MOD00                                   *}
  51. {*  PURPOSE:            Micellaneous utilities and commands.        *}
  52. {*******************************************************************}
  53.  
  54.  
  55. procedure Msg(S: AnyString);
  56. begin
  57.   GotoXY(1,24);
  58.   ClrEol;
  59.   Write(S);
  60. end;
  61.  
  62. procedure Flash(X: integer; S: AnyString;  Blink: boolean);
  63. begin
  64.   HighVideo;
  65.   GotoXY(X,23);
  66.   Write(S);
  67.   if Blink then
  68.   begin
  69.     repeat
  70.       GotoXY(X,23);
  71.       Blink:=not Blink; if Blink then HighVideo else LowVideo;
  72.       Write(S);
  73.       Delay(175);
  74.     until KeyPressed;
  75.   end;
  76.   LowVideo;
  77. end;
  78.  
  79. procedure IBMCh(var Ch: Char);
  80. begin
  81.   case Ch of
  82.     'H': Ch:=^E;
  83.     'P': Ch:=^X;
  84.     'M': Ch:=^D;
  85.     'K': Ch:=^S;
  86.     'S': Ch:=#127;
  87.     'R': Ch:=^V;
  88.     'G',
  89.     'I',
  90.     'O',
  91.     'Q': Ch:=#00;
  92.   end;
  93. end;
  94.  
  95. procedure Auto;
  96. begin
  97.   AutoCalc:=not AutoCalc;
  98.   if AutoCalc then  Flash(60,'AutoCalc: ON ',false)
  99.   else Flash(60,'AutoCalc: OFF',false);
  100. end;
  101.  
  102.  
  103. {.PA}
  104. {*******************************************************************}
  105. {*  SOURCE CODE MODULE: MC-MOD01                                   *}
  106. {*  PURPOSE:            Display grid and initialize all cells      *}
  107. {*                      in the spread sheet.                       *}
  108. {*******************************************************************}
  109.  
  110.  
  111.  
  112. procedure Grid;
  113. var I: integer;
  114.     Count: Char;
  115. begin
  116.   HighVideo;
  117.   For Count:='A' to FXMax do
  118.   begin
  119.     GotoXY(XPos[Count],1);
  120.     Write(Count);
  121.   end;
  122.   GotoXY(1,2);
  123.   for I:=1 to FYMax do writeln(I:2);
  124.   LowVideo;
  125.   if AutoCalc then  Flash(60,'AutoCalc: ON' ,false)
  126.   else Flash(60,'AutoCalc: OFF',false);
  127.   Flash(33,'  Type / for Commands',false);
  128. end;
  129.  
  130.  
  131. procedure Init;
  132. var
  133.   I: SheetIndex;
  134.   J: Integer;
  135.   LastName: string[2];
  136. begin
  137.   for I:='A' to FXMAX do
  138.   begin
  139.     for J:=1 to FYMAX do
  140.     begin
  141.       with Sheet[I,J] do
  142.       begin
  143.         CellStatus:=[Txt];
  144.         Contents:='';
  145.         Value:=0;
  146.         DEC:=2;              { Default number of decimals        }
  147.         FW:=10;              { Default field width               }
  148.       end;
  149.     end;
  150.   end;
  151.   AutoCalc:=True;
  152.   FX:='A'; FY:=1;            { First field in upper left corner  }
  153. end;
  154.  
  155. procedure Clear;
  156. begin
  157.   HighVideo;
  158.   GotoXY(1,24); ClrEol;
  159.   Write('Clear this worksheet? (Y/N) ');
  160.   repeat Read(Kbd,Ch) until Upcase(Ch) in ['Y','N'];
  161.   Write(Upcase(Ch));
  162.   if UpCase(Ch)='Y' then
  163.   begin
  164.     ClrScr;
  165.     Init;
  166.     Grid;
  167.   end;
  168. end;
  169.  
  170.  
  171.  
  172. {.PA}
  173. {*******************************************************************}
  174. {*  SOURCE CODE MODULE: MC-MOD02                                   *}
  175. {*  PURPOSE:            Display values in cells and move between   *}
  176. {*                      cells in the spread sheet.                 *}
  177. {*******************************************************************}
  178.  
  179.  
  180. procedure FlashType;
  181. begin
  182.   with Sheet[FX,FY] do
  183.   begin
  184.     GotoXY(1,23);
  185.     Write(FX,FY:2,' ');
  186.     if Formula in CellStatus  then write('Formula:')  else
  187.     if Constant in CellStatus then Write('Numeric ') else
  188.     if Txt in CellStatus then Write('Text    ');
  189.     GotoXY(1,24); ClrEol;
  190.     if Formula in CellStatus then Write(Contents);
  191.   end;
  192. end;
  193.  
  194.  
  195. { The following procedures move between the Cells on the calc sheet.}
  196. { Each Cell has an associated record containing its X,Y coordinates }
  197. { and data. See the type definition for "Cell".                     }
  198.  
  199. procedure GotoCell(GX: SheetIndex; GY: integer);
  200. begin
  201.   with Sheet[GX,GY] do
  202.   begin
  203.     HighVideo;
  204.     GotoXY(XPos[GX],GY+1);
  205.     Write('           ');
  206.     GotoXY(XPos[GX],GY+1);
  207.     if Txt in CellStatus then Write(Contents)
  208.     else
  209.     begin
  210.       if DEC>=0 then Write(Value:FW:DEC)
  211.       else Write(Value:FW);
  212.     end;
  213.     FlashType;
  214.     GotoXY(XPos[GX],GY+1);
  215.   end;
  216.   LowVideo;
  217. end;
  218.  
  219. {.CP20}
  220.  
  221. procedure LeaveCell(FX:SheetIndex;FY: integer);
  222. begin
  223.   with Sheet[FX,FY] do
  224.   begin
  225.     GotoXY(XPos[FX],FY+1);
  226.     LowVideo;
  227.     if Txt in CellStatus then Write(Contents)
  228.     else
  229.     begin
  230.       if DEC>=0 then Write(Value:FW:DEC)
  231.       else Write(Value:FW);
  232.     end;
  233.   end;
  234. end;
  235.  
  236.  
  237. {.CP20}
  238.  
  239. procedure Update;
  240. var
  241.   UFX: SheetIndex;
  242.   UFY: integer;
  243. begin
  244.   ClrScr;
  245.   Grid;
  246.   for UFX:='A' to FXMax do for UFY:=1 to FYMax do
  247.   if Sheet[UFX,UFY].Contents<>'' then LeaveCell(UFX,UFY);
  248.   GotoCell(FX,FY);
  249. end;
  250.  
  251. {.CP20}
  252.  
  253. procedure MoveDown;
  254. var Start: integer;
  255. begin
  256.   LeaveCell(FX,FY);
  257.   Start:=FY;
  258.   repeat
  259.     FY:=FY+1;
  260.     if FY>FYMax then FY:=1;
  261.   until (Sheet[FX,FY].CellStatus*[OverWritten,Locked]=[]) or (FY=Start);
  262.   if FY<>Start then GotoCell(FX,FY);
  263. end;
  264.  
  265. {.CP20}
  266.  
  267. procedure MoveUp;
  268. var Start: integer;
  269. begin
  270.   LeaveCell(FX,FY);
  271.   Start:=FY;
  272.   repeat
  273.     FY:=FY-1;
  274.     if FY<1 then FY:=FYMax;
  275.   until (Sheet[FX,FY].CellStatus*[OverWritten,Locked]=[]) or (FY=Start);
  276.   if FY<>Start then GotoCell(FX,FY);
  277. end;
  278.  
  279. {.CP20}
  280.  
  281. procedure MoveRight;
  282. var Start: SheetIndex;
  283. begin
  284.   LeaveCell(FX,FY);
  285.   Start:=FX;
  286.   repeat
  287.     FX:=Succ(FX);
  288.     if FX>FXMax then
  289.     begin
  290.       FX:='A';
  291.       FY:=FY+1;
  292.       if FY>FYMax then FY:=1;
  293.     end;
  294.   until (Sheet[FX,FY].CellStatus*[OverWritten,Locked]=[]) or (FX=Start);
  295.   if FX<>Start then GotoCell(FX,FY);
  296. end;
  297.  
  298. {.CP20}
  299.  
  300. procedure MoveLeft;
  301. var Start: SheetIndex;
  302. begin
  303.   LeaveCell(FX,FY);
  304.   Start:=FX;
  305.   repeat
  306.     FX:=Pred(FX);
  307.     if FX<'A' then
  308.     begin
  309.       FX:=FXMax;
  310.       FY:=FY-1;
  311.       if FY<1 then FY:=FYMax;
  312.     end;
  313.   until (Sheet[FX,FY].CellStatus*[OverWritten,Locked]=[]) or (FX=Start);
  314.   if FX<>Start then GotoCell(FX,FY);
  315. end;
  316.  
  317.  
  318. {.PA}
  319. {*******************************************************************}
  320. {*  SOURCE CODE MODULE: MC-MOD03                                   *}
  321. {*  PURPOSE:            Read, Save and Print a spread sheet.       *}
  322. {*                      Display on-line manual.                    *}
  323. {*******************************************************************}
  324.  
  325. type
  326.   String3 = string[3];
  327.  
  328. var
  329.   FileName: string[14];
  330.   Line: string[100];
  331.  
  332. function Exist(FileN: AnyString): boolean;
  333. var F: file;
  334. begin
  335.    {$I-}
  336.    assign(F,FileN);
  337.    reset(F);
  338.    {$I+}
  339.    if IOResult<>0 then Exist:=false
  340.    else Exist:=true;
  341. end;
  342.  
  343.  
  344. procedure GetFileName(var Line: AnyString; FileType:String3);
  345. begin
  346.   Line:='';
  347.   repeat
  348.     Read(Kbd,Ch);
  349.     if Upcase(Ch) in ['A'..'Z',^M] then
  350.     begin
  351.       write(Upcase(Ch));
  352.       Line:=Line+Ch;
  353.     end;
  354.   until (Ch=^M) or (length(Line)=8);
  355.   if Ch=^M then Delete(Line,Length(Line),1);
  356.   if Line<>'' then Line:=Line+'.'+FileType;
  357. end;
  358.  
  359. {.CP20}
  360.  
  361. procedure Save;
  362. var I: SheetIndex;
  363. J: integer;
  364. begin
  365.   HighVideo;
  366.   Msg('Save: Enter filename  ');
  367.   GetFileName(Filename,'MCS');
  368.   if FileName<>'' then
  369.   begin
  370.     Assign(MCFile,FileName);
  371.     Rewrite(MCFile);
  372.     for I:='A' to FXmax do
  373.     begin
  374.       for J:=1 to FYmax do
  375.       write(MCfile,Sheet[I,J]);
  376.     end;
  377.     Grid;
  378.     Close(MCFile);
  379.     LowVideo;
  380.     GotoCell(FX,FY);
  381.   end;
  382. end;
  383.  
  384. {.CP30}
  385.  
  386. procedure Load;
  387. begin
  388.   HighVideo;
  389.   Msg('Load: Enter filename  ');
  390.   GetFileName(Filename,'MCS');
  391.   if (Filename<>'') then if (not exist(FileName)) then
  392.   repeat
  393.     Msg('File not Found: Enter another filename  ');
  394.     GetFileName(Filename,'MCS');
  395.   until exist(FileName) or (FileName='');
  396.   if FileName<>'' then
  397.   begin
  398.     ClrScr;
  399.     Msg('Please Wait. Loading definition...');
  400.     Assign(MCFile,FileName);
  401.     Reset(MCFile);
  402.     for FX:='A' to FXmax do
  403.      for FY:=1 to FYmax do read(MCFile,Sheet[FX,FY]);
  404.     FX:='A'; FY:=1;
  405.     LowVideo;
  406.     UpDate;
  407.   end;
  408.   GotoCell(FX,FY);
  409. end;
  410.  
  411.  
  412. {.PA}
  413.  
  414. procedure Print;
  415. var
  416.   I:      SheetIndex;
  417.   J,Count,
  418.   LeftMargin: Integer;
  419.   P:          string[20];
  420.   MCFile:     Text;
  421. begin
  422.   HighVideo;
  423.   Msg('Print: Enter filename "P" for Printer> ');
  424.   GetFileName(Filename,'LST');
  425.   Msg('Left margin > ');  Read(LeftMargin);
  426.   if FileName='P.LST' then FileName:='Printer';
  427.   Msg('Printing to: ' + FileName + '....');
  428.   Assign(MCFile,FileName);
  429.   Rewrite(MCFile);
  430.   For Count:=1 to 5 do Writeln(MCFile);
  431.   for J:=1 to FYmax do
  432.   begin
  433.     Line:='';
  434.     for I:='A' to FXmax do
  435.     begin
  436.       with Sheet[I,J] do
  437.       begin
  438.         while (Length(Line)<XPOS[I]-4) do Line:=Line+' ';
  439.         if (Constant in CellStatus) or (Formula in CellStatus) then
  440.         begin
  441.           if not (Locked in CellStatus) then
  442.           begin
  443.             if DEC>0 then Str(Value:FW:DEC,P) else Str(Value:FW,P);
  444.             Line:=Line+P;
  445.           end;
  446.         end else Line:=Line+Contents;
  447.       end; { With }
  448.     end; { One line }
  449.     For Count:=1 to LeftMargin do Write(MCFile,' ');
  450.     writeln(MCFile,Line);
  451.   end; { End Column }
  452.   Grid;
  453.   Close(MCFile);
  454.   LowVideo;
  455.   GotoCell(FX,FY);
  456. end;
  457.  
  458. {.PA}
  459.  
  460. procedure Help;
  461. var
  462.   H: text;
  463.   Line: string[80];
  464.   J: integer;
  465.   Bold: boolean;
  466.  
  467. begin
  468.   if Exist('CALC.HLP') then
  469.   begin
  470.     Assign(H,'CALC.HLP');
  471.     Reset(H);
  472.     while not Eof(H) do
  473.     begin
  474.       ClrScr; Bold:=false; LowVideo;
  475.       Readln(H,Line);
  476.       repeat
  477.         Write('     ');
  478.         For J:=1 to Length(Line) do
  479.         begin
  480.           if Line[J]=^B then
  481.           begin
  482.             Bold:=not Bold;
  483.             if Bold then HighVideo else LowVideo;
  484.           end else write(Line[J]);
  485.         end;
  486.         Writeln;
  487.         Readln(H,Line);
  488.       until  Eof(H) or (Copy(Line,1,3)='.PA');
  489.       GotoXY(26,24); HighVideo;
  490.       write('<<< Please press any key to continue >>>');
  491.       LowVideo;
  492.       read(Kbd,Ch);
  493.     end;
  494.     GotoXY(20,24); HighVideo;
  495.     write('<<< Please press <RETURN> to start MicroCalc >>>');
  496.     LowVideo;
  497.     Readln(Ch);
  498.     UpDate;
  499.   end else { Help file did not exist }
  500.   begin
  501.     Msg('To get help the file CALC.HLP must be on your disk. Press <RETURN>');
  502.     repeat Read(kbd,Ch) until Ch=^M;
  503.     GotoCell(FX,FY);
  504.   end;
  505. end;
  506.  
  507.  
  508. {.PA}
  509. {*******************************************************************}
  510. {*  SOURCE CODE MODULE: MC-MOD04                                   *}
  511. {*  PURPOSE:            Evaluate formulas.                         *}
  512. {*                      Recalculate spread sheet.                  *}
  513. {*                                                                 *}
  514. {*  NOTE:               This module contains recursive procedures  *}
  515. {*******************************************************************}
  516.  
  517. var
  518.   Form: Boolean;
  519.  
  520. {$A-}
  521. procedure Evaluate(var IsFormula: Boolean; { True if formula}
  522.                    var Formula: AnyString; { Fomula to evaluate}
  523.                    var Value: Real;  { Result of formula }
  524.                    var ErrPos: Integer);{ Position of error }
  525. const
  526.   Numbers: set of Char = ['0'..'9'];
  527.   EofLine  = ^M;
  528.  
  529. var
  530.   Pos: Integer;    { Current position in formula                     }
  531.   Ch: Char;        { Current character being scanned                 }
  532.   EXY: string[3];  { Intermidiate string for conversion              }
  533.  
  534. { Procedure NextCh returns the next character in the formula         }
  535. { The variable Pos contains the position ann Ch the character        }
  536.  
  537.   procedure NextCh;
  538.   begin
  539.     repeat
  540.       Pos:=Pos+1;
  541.       if Pos<=Length(Formula) then
  542.       Ch:=Formula[Pos] else Ch:=eofline;
  543.     until Ch<>' ';
  544.   end  { NextCh };
  545.  
  546.  
  547.   function Expression: Real;
  548.   var
  549.     E: Real;
  550.     Opr: Char;
  551.  
  552.     function SimpleExpression: Real;
  553.     var
  554.       S: Real;
  555.       Opr: Char;
  556.  
  557.       function Term: Real;
  558.       var
  559.         T: Real;
  560.  
  561.         function SignedFactor: Real;
  562.  
  563.           function Factor: Real;
  564.           type
  565.             StandardFunction = (fabs,fsqrt,fsqr,fsin,fcos,
  566.             farctan,fln,flog,fexp,ffact);
  567.             StandardFunctionList = array[StandardFunction] of string[6];
  568.  
  569.           const
  570.             StandardFunctionNames: StandardFunctionList =('ABS','SQRT','SQR','SIN','COS',
  571.                                                           'ARCTAN','LN','LOG','EXP','FACT');
  572.           var
  573.             E,EE,L:  Integer;       { intermidiate variables }
  574.             Found:Boolean;
  575.             F: Real;
  576.             Sf:StandardFunction;
  577.             OldEFY,                 { Current cell  }
  578.             EFY,
  579.             SumFY,
  580.             Start:Integer;
  581.             OldEFX,
  582.             EFX,
  583.             SumFX:SheetIndex;
  584.             CellSum: Real;
  585.  
  586.               function Fact(I: Integer): Real;
  587.               begin
  588.                 if I > 0 then begin Fact:=I*Fact(I-1); end
  589.                 else Fact:=1;
  590.               end  { Fact };
  591.  
  592. {.PA}
  593.           begin { Function Factor }
  594.             if Ch in Numbers then
  595.             begin
  596.               Start:=Pos;
  597.               repeat NextCh until not (Ch in Numbers);
  598.               if Ch='.' then repeat NextCh until not (Ch in Numbers);
  599.               if Ch='E' then
  600.               begin
  601.                 NextCh;
  602.                 repeat NextCh until not (Ch in Numbers);
  603.               end;
  604.               Val(Copy(Formula,Start,Pos-Start),F,ErrPos);
  605.             end else
  606.             if Ch='(' then
  607.             begin
  608.               NextCh;
  609.               F:=Expression;
  610.               if Ch=')' then NextCh else ErrPos:=Pos;
  611.             end else
  612.             if Ch in ['A'..'G'] then { Maybe a cell reference }
  613.             begin
  614.               EFX:=Ch;
  615.               NextCh;
  616.               if Ch in Numbers then
  617.               begin
  618.                 F:=0;
  619.                 EXY:=Ch; NextCh;
  620.                 if Ch in Numbers then
  621.                 begin
  622.                   EXY:=EXY+Ch;
  623.                   NextCh;
  624.                 end;
  625.                 Val(EXY,EFY,ErrPos);
  626.                 IsFormula:=true;
  627.                 if (Constant in Sheet[EFX,EFY].CellStatus) and
  628.                 not (Calculated in Sheet[EFX,EFY].CellStatus) then
  629.                 begin
  630.                   Evaluate(Form,Sheet[EFX,EFY].contents,f,ErrPos);
  631.                   Sheet[EFX,EFY].CellStatus:=Sheet[EFX,EFY].CellStatus+[Calculated]
  632.                 end else if not (Txt in Sheet[EFX,EFY].CellStatus) then
  633.                 F:=Sheet[EFX,EFY].Value;
  634.                 if Ch='>' then
  635.                 begin
  636.                   OldEFX:=EFX; OldEFY:=EFY;
  637.                   NextCh;
  638.                   EFX:=Ch;
  639.                   NextCh;
  640.                   if Ch in Numbers then
  641.                   begin
  642.                     EXY:=Ch;
  643.                     NextCh;
  644.                     if Ch in Numbers then
  645.                     begin
  646.                       EXY:=EXY+Ch;
  647.                       NextCh;
  648.                     end;
  649.                     val(EXY,EFY,ErrPos);
  650.                     Cellsum:=0;
  651.                     for SumFY:=OldEFY to EFY do
  652.                     begin
  653.                       for SumFX:=OldEFX to EFX do
  654.                       begin
  655.                         F:=0;
  656.                         if (Constant in Sheet[SumFX,SumFY].CellStatus) and
  657.                         not (Calculated in Sheet[SumFX,SumFY].CellStatus) then
  658.                         begin
  659.                           Evaluate(Form,Sheet[SumFX,SumFY].contents,f,errPos);
  660.                           Sheet[SumFX,SumFY].CellStatus:=
  661.                           Sheet[SumFX,SumFY].CellStatus+[Calculated];
  662.                         end else if not (Txt in Sheet[SumFX,SumFY].CellStatus) then
  663.                         F:=Sheet[SumFX,SumFY].Value;
  664.                         Cellsum:=Cellsum+f;
  665.                         f:=Cellsum;
  666.                       end;
  667.                     end;
  668.                   end;
  669.                 end;
  670.               end;
  671.             end else
  672.             begin
  673.               found:=false;
  674.               for sf:=fabs to ffact do
  675.               if not found then
  676.               begin
  677.                 l:=Length(StandardFunctionNames[sf]);
  678.                 if copy(Formula,Pos,l)=StandardFunctionNames[sf] then
  679.                 begin
  680.                   Pos:=Pos+l-1; NextCh;
  681.                   F:=Factor;
  682.                   case sf of
  683.                     fabs:     f:=abs(f);
  684.                     fsqrt:    f:=sqrt(f);
  685.                     fsqr:     f:=sqr(f);
  686.                     fsin:     f:=sin(f);
  687.                     fcos:     f:=cos(f);
  688.                     farctan:  f:=arctan(f);
  689.                     fln :     f:=ln(f);
  690.                     flog:     f:=ln(f)/ln(10);
  691.                     fexp:     f:=exp(f);
  692.                     ffact:    f:=fact(trunc(f));
  693.                   end;
  694.                   Found:=true;
  695.                 end;
  696.               end;
  697.               if not Found then ErrPos:=Pos;
  698.             end;
  699.             Factor:=F;
  700.           end { function Factor};
  701. {.PA}
  702.  
  703.         begin { SignedFactor }
  704.           if Ch='-' then
  705.           begin
  706.             NextCh; SignedFactor:=-Factor;
  707.           end else SignedFactor:=Factor;
  708.         end { SignedFactor };
  709.  
  710.       begin { Term }
  711.         T:=SignedFactor;
  712.         while Ch='^' do
  713.         begin
  714.           NextCh; t:=exp(ln(t)*SignedFactor);
  715.         end;
  716.         Term:=t;
  717.       end { Term };
  718.  
  719.  
  720.     begin { SimpleExpression }
  721.       s:=term;
  722.       while Ch in ['*','/'] do
  723.       begin
  724.         Opr:=Ch; NextCh;
  725.         case Opr of
  726.           '*': s:=s*term;
  727.           '/': s:=s/term;
  728.         end;
  729.       end;
  730.       SimpleExpression:=s;
  731.     end { SimpleExpression };
  732.  
  733.   begin { Expression }
  734.     E:=SimpleExpression;
  735.     while Ch in ['+','-'] do
  736.     begin
  737.       Opr:=Ch; NextCh;
  738.       case Opr of
  739.         '+': e:=e+SimpleExpression;
  740.         '-': e:=e-SimpleExpression;
  741.       end;
  742.     end;
  743.     Expression:=E;
  744.   end { Expression };
  745.  
  746.  
  747. begin { procedure Evaluate }
  748.   if Formula[1]='.' then Formula:='0'+Formula;
  749.   if Formula[1]='+' then delete(Formula,1,1);
  750.   IsFormula:=false;
  751.   Pos:=0; NextCh;
  752.   Value:=Expression;
  753.   if Ch=EofLine then ErrPos:=0 else ErrPos:=Pos;
  754. end { Evaluate };
  755.  
  756. {.PA}
  757.  
  758. procedure Recalculate;
  759. var
  760.   RFX: SheetIndex;
  761.   RFY:integer;
  762.   OldValue: real;
  763.   Err: integer;
  764.  
  765. begin
  766.   LowVideo;
  767.   GotoXY(1,24); ClrEol;
  768.   Write('Calculating..');
  769.   for RFY:=1 to FYMax do
  770.   begin
  771.     for RFX:='A' to FXMax do
  772.     begin
  773.       with Sheet[RFX,RFY] do
  774.       begin
  775.         if (Formula in CellStatus) then
  776.         begin
  777.           CellStatus:=CellStatus+[Calculated];
  778.           OldValue:=Value;
  779.           Evaluate(Form,Contents,Value,Err);
  780.           if OldValue<>Value then
  781.           begin
  782.             GotoXY(XPos[RFX],RFY+1);
  783.             if (DEC>=0) then Write(Value:FW:DEC)
  784.             else Write(Value:FW);
  785.           end;
  786.         end;
  787.       end;
  788.     end;
  789.   end;
  790.   GotoCell(FX,FY);
  791. end;
  792.  
  793. {.PA}
  794. {*******************************************************************}
  795. {*  SOURCE CODE MODULE: MC-MOD05                                   *}
  796. {*  PURPOSE:            Read the contents of a cell and update     *}
  797. {*                      associated cells.                          *}
  798. {*******************************************************************}
  799.  
  800.  
  801. procedure GetLine(var S: AnyString;           { String to edit       }
  802.                          ColNO,LineNO,        { Where start line     }
  803.                          MAX,                 { Max length           }
  804.                          ErrPos: integer;     { Where to begin       }
  805.                          UpperCase:Boolean);  { True if auto Upcase  }
  806. var
  807.   X: integer;
  808.   InsertOn: boolean;
  809.   OkChars: set of Char;
  810.  
  811.  
  812.   procedure GotoX;
  813.   begin
  814.     GotoXY(X+ColNo-1,LineNo);
  815.   end;
  816.  
  817. begin
  818.   OkChars:=[' '..'}'];
  819.   InsertOn:=true;
  820.   X:=1; GotoX;
  821.   Write(S);
  822.   if Length(S)=1 then X:=2;
  823.   if ErrPos<>0 then X:=ErrPos;
  824.   GotoX;
  825.   repeat
  826.     Read(Kbd,Ch);
  827.     if KeyPressed then
  828.     begin
  829.       Read(kbd,Ch);
  830.       IBMCh(Ch);
  831.     end;
  832.     if UpperCase then Ch:=UpCase(Ch);
  833.     case Ch of
  834.        ^[: begin
  835.              S:=chr($FF); { abort editing }
  836.              Ch:=^M;
  837.            end;
  838.        ^D: begin { Move cursor right }
  839.              X:=X+1;
  840.              if (X>length(S)+1) or (X>MAX) then X:=X-1;
  841.              GotoX;
  842.            end;
  843.        ^G: begin { Delete right char }
  844.              if X<=Length(S) then
  845.              begin
  846.                Delete(S,X,1);
  847.                Write(copy(S,X,Length(S)-X+1),' ');
  848.                GotoX;
  849.              end;
  850.            end;
  851.     ^S,^H: begin { Move cursor left }
  852.              X:=X-1;
  853.              if X<1 then X:=1;
  854.              GotoX;
  855.            end;
  856.        ^F: begin { Move cursor to end of line }
  857.               X:=Length(S)+1;
  858.               GotoX;
  859.            end;
  860.        ^A: begin { Move cursor to beginning of line }
  861.              X:=1;
  862.              GotoX;
  863.            end;
  864.      #127: begin { Delete left char }
  865.              X:=X-1;
  866.              if (Length(S)>0) and (X>0)  then
  867.              begin
  868.                Delete(S,X,1);
  869.                Write(copy(S,X,Length(S)-X+1),' ');
  870.                GotoX;
  871.                if X<1 then X:=1;
  872.              end else X:=1;
  873.            end;
  874.        ^V: InsertOn:= not InsertOn;
  875.  
  876. {.PA}
  877.  
  878.     else
  879.       begin
  880.         if Ch in OkChars  then
  881.         begin
  882.           if InsertOn then
  883.           begin
  884.             insert(Ch,S,X);
  885.             Write(copy(S,X,Length(S)-X+1),' ');
  886.           end else
  887.           begin
  888.             write(Ch);
  889.             if X=length(S) then S:=S+Ch
  890.               else S[X]:=Ch;
  891.           end;
  892.           if Length(S)+1<=MAX then X:=X+1
  893.           else OkChars:=[]; { Line too Long }
  894.           GotoX;
  895.         end else
  896.         if Length(S)+1<=Max then
  897.           OkChars:= [' '..'}']; { Line ok again }
  898.       end;
  899.     end;
  900.   until CH=^M;
  901. end;
  902.  
  903.  
  904. {.PA}
  905.  
  906.  
  907. procedure  GetCell(FX: SheetIndex;FY: Integer);
  908. var
  909.   S:             AnyString;
  910.   NewStat:       Set of Attributes;
  911.   ErrorPosition: Integer;
  912.   I:             SheetIndex;
  913.   Result:        Real;
  914.   Abort:         Boolean;
  915.   IsForm:        Boolean;
  916.  
  917. { Procedure ClearCells clears the current cell and its associated    }
  918. { cells. An associated cell is a cell overwritten by data from the   }
  919. { current cell. The data can be text in which case the cell has the  }
  920. { attribute "OverWritten". If the data is a result from an expression}
  921. { and the field with is larger tahn 11 then the cell is "Locked"     }
  922.  
  923.   procedure ClearCells;
  924.   begin
  925.     I:=FX;
  926.     repeat
  927.       with Sheet[I,FY] do
  928.       begin
  929.         GotoXY(XPos[I],FY+1);
  930.         write('           '); I:=Succ(I);
  931.       end;
  932.     until ([OverWritten,Locked]*Sheet[I,FY].CellStatus=[]);
  933.     { Cell is not OVerWritten not Locked }
  934.   end;
  935.  
  936. {.CP20}
  937. { The new type of the cell is flashed at the bottom of the Sheet     }
  938. { Notice that a constant of type array is used to indicate the type  }
  939.  
  940.   procedure FlashType;
  941.   begin
  942.     HighVideo;
  943.     GotoXY(5,23);
  944.     LowVideo;
  945.   end;
  946.  
  947. {.CP20}
  948.   procedure GetFormula;
  949.   begin
  950.     FlashType;
  951.     repeat
  952.       GetLine(S,1,24,70,ErrorPosition,True);
  953.       if S<>Chr($FF) then
  954.       begin
  955.         Evaluate(IsForm,S,Result,ErrorPosition);
  956.         if ErrorPosition<>0 then
  957.           Flash(15,'Error at cursor'+^G,false)
  958.         else Flash(15,'               ',false);
  959.       end;
  960.     until (ErrorPosition=0) or (S=Chr($FF));
  961.     if IsForm then NewStat:=NewStat+[Formula];
  962.   end;
  963.  
  964. {.CP20}
  965. { Procedure GetText calls the procedure GetLine with the current     }
  966. { cells X,Y position as parameters. This means that text entering    }
  967. { takes place direcly at the cells position on the Sheet.            }
  968.  
  969.   procedure GetText;
  970.   begin
  971.     FlashType;
  972.     with Sheet[FX,FY] do GetLine(S,XPos[FX],FY+1,70,ErrorPosition,False);
  973.   end;
  974.  
  975. {.CP20}
  976. { Procedure EditCell loads a copy of the current cells contents in   }
  977. { in the variable S before calling either GetText or GetFormula. In  }
  978. { this way no changes are made to the current cell.                  }
  979.  
  980.   procedure EditCell;
  981.   begin
  982.     with Sheet[FX,FY] do
  983.     begin
  984.       S:=Contents;
  985.       if Txt in CellStatus then GetText else GetFormula;
  986.     end;
  987.   end;
  988.  
  989. {.PA}
  990. { Procedure UpdateCells is a little more complicated. Basically it   }
  991. { makes sure to tag and untag cells which has been overwritten or    }
  992. { cleared from data from  another cell. It also updates the current  }
  993. { with the new type and the contents which still is in the temporaly }
  994. { variable "S".                                                      }
  995.  
  996.  
  997.   procedure UpdateCells;
  998.   var
  999.     Flength: Integer;
  1000.   begin
  1001.     Sheet[FX,FY].Contents:=S;
  1002.     if Txt in NewStat {Sheet[FX,FY].CellStatus} then
  1003.     begin
  1004.       I:=FX; FLength:=Length(S);
  1005.       repeat
  1006.         I:=Succ(I);
  1007.         with Sheet[I,FY] do
  1008.         begin
  1009.           FLength:=Flength-11;
  1010.           if (Flength>0) then
  1011.           begin
  1012.             CellStatus:=[Overwritten,Txt];
  1013.             Contents:='';
  1014.           end else
  1015.           begin
  1016.             if OverWritten in CellStatus then
  1017.             begin
  1018.               CellStatus:=[Txt];
  1019.               GotoCell(I,FY);LeaveCell(I,FY);
  1020.             end;
  1021.           end;
  1022.         end;
  1023.       until (I=FXMax)  or (Sheet[I,FY].Contents<>'');
  1024.       Sheet[FX,FY].CellStatus:=[Txt];
  1025.     end else { string changed to formula or constant }
  1026.     begin { Event number two }
  1027.       I:=FX;
  1028.       repeat
  1029.         with Sheet[I,FY] do
  1030.         begin
  1031.           if OverWritten in CellStatus then
  1032.           begin
  1033.             CellStatus:=[Txt];
  1034.             Contents:='';
  1035.           end;
  1036.           I:=Succ(I);
  1037.         end;
  1038.       until not (OverWritten in Sheet[I,FY].CellStatus);
  1039.       with Sheet[FX,FY] do
  1040.       begin
  1041.         CellStatus:=[Constant];
  1042.         if IsForm then CellStatus:=CellStatus+[Formula];
  1043.         Value:=Result;
  1044.       end;
  1045.     end;
  1046.   end;
  1047.  
  1048.  
  1049. {.PA}
  1050. { Procedure GetCell finnaly starts here. This procedure uses all     }
  1051. { all the above local procedures. First it initializes the temporaly }
  1052. { variable "S" with the last read character. It then depending on    }
  1053. { this character calls GetFormula, GetText, or EditCell.             }
  1054.  
  1055. begin { procedure GetCell }
  1056.   S:=Ch; ErrorPosition:=0; Abort:=false;
  1057.   NewStat:=[];
  1058.   if Ch in ['0'..'9','+','-','.','(',')'] then
  1059.   begin
  1060.     NewStat:=[Constant];
  1061.     if not (Formula in Sheet[FX,FY].CellStatus) then
  1062.     begin
  1063.       GotoXY(11,24); ClrEol;
  1064.       ClearCells;
  1065.       GetFormula;
  1066.     end else
  1067.     begin
  1068.       Flash(15,'Edit formula Y/N?',true);
  1069.       repeat read(Kbd,Ch) until UpCase(CH) in ['Y','N'];
  1070.       Flash(15,'                 ',false);
  1071.       if UpCase(Ch)='Y' then EditCell Else Abort:=true;
  1072.     end;
  1073.   end else
  1074.   begin
  1075.     if Ch=^[ then
  1076.     begin
  1077.       NewStat:=(Sheet[FX,FY].CellStatus)*[Txt,Constant];
  1078.       EditCell;
  1079.     end else
  1080.     begin
  1081.       if formula in Sheet[FX,FY].CellStatus then
  1082.       begin
  1083.         Flash(15,'Edit formula Y/N?',true);
  1084.         repeat read(Kbd,Ch) until UpCase(CH) in ['Y','N'];
  1085.         Flash(15,'                 ',false);
  1086.         if UpCase(Ch)='Y' then EditCell Else Abort:=true;
  1087.       end else
  1088.       begin
  1089.         NewStat:=[Txt];
  1090.         ClearCells;
  1091.         GetText;
  1092.       end;
  1093.     end;
  1094.   end;
  1095.   if not Abort then
  1096.   begin
  1097.     if S<>Chr($FF) then UpDateCells;
  1098.     GotoCell(FX,FY);
  1099.     if AutoCalc and (Constant in Sheet[FX,FY].CellStatus) then Recalculate;
  1100.     if Txt in NewStat then
  1101.     begin
  1102.       GotoXY(3,FY+1); Clreol;
  1103.       For I:='A' to FXMax do
  1104.       LeaveCell(I,FY);
  1105.     end;
  1106.   end;
  1107.   Flash(15,'                ',False);
  1108.   GotoCell(FX,FY);
  1109. end;
  1110.  
  1111. {.PA}
  1112. { Procedure Format is used to }
  1113.  
  1114.  
  1115. procedure Format;
  1116. var
  1117.   J,FW,DEC,
  1118.   FromLine,ToLine: integer;
  1119.   Lock:            Boolean;
  1120.  
  1121.  
  1122.   procedure GetInt(var I: integer; Max: Integer);
  1123.   var
  1124.     S: string[8];
  1125.     Err: Integer;
  1126.     Ch: Char;
  1127.   begin
  1128.     S:='';
  1129.     repeat
  1130.       repeat Read(Kbd,Ch) until Ch in ['0'..'9','-',^M];
  1131.       if Ch<>^M then
  1132.       begin
  1133.         Write(Ch); S:=S+Ch;
  1134.         Val(S,I,Err);
  1135.       end;
  1136.     until (I>=Max) or (Ch=^M);
  1137.     if I>Max then I:=Max;
  1138.   end;
  1139.  
  1140. begin
  1141.   HighVideo;
  1142.   Msg('Format: Enter number of decimals (Max 11):  ');
  1143.   GetInt(DEC,11);
  1144.   Msg('Enter Cell whith remember if larger than 10 next column will lock: ');
  1145.   GetInt(FW,20);
  1146.   Msg('From which line in column '+FX+': ');
  1147.   GetInt(FromLine,FYMax);
  1148.   Msg('To which line in column '+FX+': ');
  1149.   GetInt(ToLine,FYMax);
  1150.   if FW>10 then Lock:=true else Lock:=False;
  1151.   for J:=FromLine to ToLine do
  1152.   begin
  1153.     Sheet[FX,J].DEC:=DEC;
  1154.     Sheet[FX,J].FW:=FW;
  1155.     with Sheet[Succ(FX),J] do
  1156.     begin
  1157.       if Lock then
  1158.       begin
  1159.         CellStatus:=CellStatus+[Locked,Txt];
  1160.         Contents:='';
  1161.       end else CellStatus:=CellStatus-[Locked];
  1162.     end;
  1163.   end;
  1164.   NormVideo;
  1165.   UpDate;
  1166.   GotoCell(FX,FY);
  1167. end;
  1168.  
  1169.  
  1170. {.PA}
  1171. {*********************************************************************}
  1172. {*                START OF MAIN PROGRAM PROCEDURES                   *}
  1173. {*********************************************************************}
  1174.  
  1175.  
  1176. { Procedure Commands is activated from the main loop in this program }
  1177. { when the user types a slash (/). a procedure activates a procedure}
  1178. { which will execute the command. These procedures are located in the}
  1179. { above modules.                                                     }
  1180.  
  1181. { For easy reference the source code module number is shown in a     }
  1182. { comment on the right following the procedure call.                 }
  1183.  
  1184. procedure Commands;
  1185. begin
  1186.   GotoXY(1,24);
  1187.   HighVideo;
  1188.   Write('/ restore Quit, Load, Save, Recalculate, Print, Format, AutoCalc, Help ');
  1189.   Read(Kbd,Ch);
  1190.   Ch:=UpCase(Ch);
  1191.   case Ch of                                             { In module }
  1192.     'Q': Halt;
  1193.     'F': Format;                                               {  04 }
  1194.     'S': Save;                                                 {  03 }
  1195.     'L': Load;                                                 {  03 }
  1196.     'H': Help;                                                 {  03 }
  1197.     'R': Recalculate;                                          {  05 }
  1198.     'A': Auto;                                                 {  00 }
  1199.     '/': Update;                                               {  01 }
  1200.     'C': Clear;                                                {  01 }
  1201.     'P': Print;                                                {  03 }
  1202.   end;
  1203.   Grid;                                                        {  01 }
  1204.   GotoCell(FX,FY);                                             {  02 }
  1205. end;
  1206.  
  1207. { Procedure Hello says hello and activates the help procedure if the }
  1208. { user presses anything but Return                                   }
  1209.  
  1210. procedure Welcome;
  1211.  
  1212.   procedure Center(S: AnyString);
  1213.   var I: integer;
  1214.   begin
  1215.     for I:=1 to (80-Length(S)) div 2 do Write(' ');
  1216.     writeln(S);
  1217.   end;
  1218.  
  1219. begin { procedure Wellcome }
  1220.   ClrScr; GotoXY(1,9);
  1221.   Center('Welcome to MicroCalc.  A Turbo demonstation program');
  1222.   Center('Press any key for help or <RETURN> to start');
  1223.   GotoXY(40,12);
  1224.   Read(Kbd,Ch);
  1225.   if Ch<>^M then Help;
  1226. end;
  1227.  
  1228. {.PA}
  1229. {*********************************************************************}
  1230. {*          THIS IS WHERE THE PROGRAM STARTS EXECUTING               *}
  1231. {*********************************************************************}
  1232.  
  1233. begin
  1234.   Init;                                                        {  01 }
  1235.   Welcome;
  1236.   ClrScr; Grid;                                                {  01 }
  1237.   GotoCell(FX,FY);
  1238.   repeat
  1239.     Read(Kbd,Ch);
  1240.     if KeyPressed then
  1241.     begin
  1242.       read(kbd,Ch);
  1243.       IBMCh(Ch);
  1244.     end;
  1245.     case Ch of
  1246.       ^E:       MoveUp;                                        {  02 }
  1247.       ^X,^J:    MoveDown;                                      {  02 }
  1248.       ^D,^M,^F: MoveRight;                                     {  02 }
  1249.       ^S,^A:    MoveLeft;                                      {  02 }
  1250.       '/':      Commands;
  1251.       ^[:       GetCell(FX,FY);                                {  04 }
  1252.     else
  1253.       if Ch in [' '..'~'] then
  1254.       GetCell(FX,FY);                                          {  04 }
  1255.     end;
  1256.   until true=false;          { (program stops in procedure Commands) }
  1257. end.
  1258.  
  1259.